package com.socodethis.spaceex;

import java.util.ArrayList;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.socodethis.spaceex.math.cPoint;

public class spriteAnimate {
	Sprite[] spriteUpLeft,spriteUpRight,spriteDownLeft,spriteDownRight;
	private int direction;
	//0=UL 1=UR 2=DL 3=DR
	private int animCycle;
	private float tWidth, tHeight, transWidth, transHeight;
	private float lastTime, interval, standingCount, sCounter, rotation;
	private cPoint position, lastPosition,size, destination;
	private ArrayList<cPoint> animatePath;
	private boolean moving, changingDirections, computerPlayer;
	private saveState save;
	private shortestPath path;
	public spriteAnimate(Sprite[] spriteUpLeft,Sprite[] spriteUpRight,Sprite[] spriteDownLeft,Sprite[] spriteDownRight, 
			cPoint start, cPoint origin, float rotation, boolean computerPlayer, float speed){
		size = new cPoint((float) Math.sqrt(3),2);
		direction = 3;
		animCycle = 0;
		lastTime = 0;
		transWidth = 0;
		transHeight = 0;
		moving = false;
		changingDirections = false;
		this.computerPlayer = computerPlayer;
		//The speed of the animation. Smaller = faster
		interval = speed;
		standingCount = 5;
		this.rotation = rotation;
		//Starting position of the sprite
		this.size = new cPoint(size);
		position = new cPoint(start.getX(),start.getY());
		destination = new cPoint(position);
		lastPosition = new cPoint(position.getX(),position.getY());
		//Loads the sprite directions into the class. Should be done better than this
		this.spriteUpLeft = new Sprite[spriteUpLeft.length];
		this.spriteUpRight = new Sprite[spriteUpRight.length];
		this.spriteDownLeft = new Sprite[spriteDownLeft.length];
		this.spriteDownRight = new Sprite[spriteDownRight.length];
		for(int i = 0; i < spriteUpLeft.length; i++){
			this.spriteUpLeft[i] = spriteUpLeft[i];
			this.spriteUpLeft[i].setSize(size.getX(), size.getY());
			this.spriteUpLeft[i].setOrigin(0, 0);
			this.spriteUpLeft[i].rotate(rotation);
		}
		for(int i = 0; i < spriteUpLeft.length; i++){
			this.spriteUpRight[i] = spriteUpRight[i];
			this.spriteUpRight[i].setSize(size.getX(), size.getY());
			this.spriteUpRight[i].setOrigin(0, 0);
			this.spriteUpRight[i].rotate(rotation);
		}
		for(int i = 0; i < spriteUpLeft.length; i++){
			this.spriteDownLeft[i] = spriteDownLeft[i];
			this.spriteDownLeft[i].setSize(size.getX(), size.getY());
			this.spriteDownLeft[i].setOrigin(0, 0);
			this.spriteDownLeft[i].rotate(rotation);
		}
		for(int i = 0; i < spriteUpLeft.length; i++){
			this.spriteDownRight[i] = spriteDownRight[i];
			this.spriteDownRight[i].setSize(size.getX(), size.getY());
			this.spriteDownRight[i].setOrigin(0, 0);
			this.spriteDownRight[i].rotate(rotation);
		}
		animatePath = new ArrayList<cPoint>();
	}
	public cPoint getPosition(){
		return lastPosition;
	}
	public cPoint getTransitionPath(){
		return position;
	}
	public cPoint getScale(){
		return size;
	}
	public float getRotation(){
		return rotation;
	}
	public float returnDirection(){
		return direction;
	}
	//Calculates the direction of the character's movement from the shortestPath array
	public void calcDirection(cPoint end){
		if(end.getX()>position.getX()){
			direction = 2;
		}
		else if(end.getX()<position.getX()){
			direction = 1;
		}
		else if(end.getY()>position.getY()){
			direction = 3;
		}
		else if(end.getY()<position.getY()){
			direction = 0;
		}
	}
	//Checks to see if it is time to move on to the next frame
	private boolean getTransitionChange(){
		if(Math.abs(transWidth)>=1 || Math.abs(transHeight)>=1){
			return true;
		}
		return false;
	}
	//Sets the transitions to zero if the character isn't moving
	public cPoint getTransitionCount(){
		if (moving){
			return new cPoint(transWidth,transHeight);
		}else{
			return new cPoint(0,0);
		}
	}
	//Adds a percentage of the frame to the animation, so that the movement looks fluid when the character travels
	public void incrementTransition(){
		if(direction == 2){
			transWidth += 1/tWidth;
		}
		else if(direction == 1){
			transWidth -= 1/tWidth;
		}
		else if(direction == 3){
			transHeight += 1/tHeight;
		}
		else if(direction == 0){
			transHeight -= 1/tHeight;
		}
	}
	//Returns a flag if the character is moving
	public boolean isMoving(){
		return moving;
	}
	
	public cPoint getDestination(){
		return destination;
	}
	//Finds the shortest path and loads it into the class
	public void setSpritePath(dungeonGenerator dungeon, cPoint end){
		tWidth = 3;
		tHeight = 3;
		if(!moving){
			destination = new cPoint(end);
			if(!computerPlayer){
				path = new shortestPath(dungeon.getObstacleMap(),lastPosition, end,(int)dungeon.getDimensions().getX(),(int)dungeon.getDimensions().getY());
				animatePath = new ArrayList<cPoint>(path.returnPath());
			}else{
				path = new shortestPath(dungeon.getEnemyMap(),lastPosition, end,(int)dungeon.getDimensions().getX(),(int)dungeon.getDimensions().getY());
				animatePath = new ArrayList<cPoint>(path.returnPath());
			}
			position.setPoint(lastPosition.getX(),lastPosition.getY());
			/*if(animatePath.size()>=2){
				transitionPath.setPoint(animatePath.get(0).getX(), animatePath.get(0).getY());
			}else{
				transitionPath.setPoint(end.getX(),end.getY());
			}*/
		//this has to be here so the character does not sputter when the player changes directions mid-walk
		}else{
			save = new saveState(dungeon,end);
			changingDirections =true;
		}
	}
	
	//Moves the character fluidly depending on the map units (in tiledLoader) and interval (declared in constructor)
	public void calculateTransitions(float currentTime){
		if(currentTime > lastTime + interval){
			if(isMoving()){
				sCounter = 0;
				animCycle++;
			}else{
				if(sCounter >=standingCount){
					sCounter = 0;
					animCycle++;
				}
				sCounter++;
			}
			lastTime = currentTime;
			if(animatePath.size() > 1 && (getTransitionChange()||!moving)){
				//If the another location hasn't been clicked while the player is moving, move the player
				if(!changingDirections){
					moving = true;
					transHeight = 0;
					transWidth = 0;
					animatePath.remove(0);
					calcDirection(new cPoint(animatePath.get(0).getX(),animatePath.get(0).getY()));
					lastPosition.setPoint(position.getX(), position.getY());
					position.setPoint(animatePath.get(0).getX(), animatePath.get(0).getY());
					/*if(animatePath.size()>=2){
						transitionPath.setPoint(animatePath.get(0).getX(), animatePath.get(0).getY());
					}else{
						transitionPath.setPoint(position.getX(),position.getY());
					}*/
				//If another location has been clicked, create a new path when the player reaches his next tile
				}else{
					changingDirections = false;
					moving = false;
					//transitionPath.setPoint(lastPosition.getX(),lastPosition.getY());
					lastPosition.setPoint(position.getX(), position.getY());
					setSpritePath(save.map,save.end);
				}
			//If there is still more in the stack, then keep transitioning
			}else if ((animatePath.size() > 1 || !lastPosition.cEquals(position)) && !getTransitionChange()){
				incrementTransition();
			//If there is nothing in the stack, but the two positions are not yet equal
			}else if(animatePath.size() <= 1 && !lastPosition.cEquals(position) && getTransitionChange()){
				if(!changingDirections){
					moving = false;
					//transitionPath.setPoint(lastPosition.getX(),lastPosition.getY());
					lastPosition.setPoint(position.getX(), position.getY());
				}else{
					changingDirections = false;
					moving = false;
					//transitionPath.setPoint(lastPosition.getX(),lastPosition.getY());
					lastPosition.setPoint(position.getX(), position.getY());
					setSpritePath(save.map,save.end);
				}
			//Everything equal nothing in stack, stop animation. Logically should never reach here
			}else{
				moving = false;
			}
		}
	}
	
	public void stopCharacter(){
		moving = false;
		transHeight = 0;
		transWidth = 0;
		animatePath.clear();
		position.setPoint(lastPosition.getX(), lastPosition.getY());
	}
	
	public void setPosition(cPoint position){
		moving = false;
		transHeight = 0;
		transWidth = 0;
		animatePath.clear();
		this.position.setPoint(position.getX(), position.getY());
		lastPosition.setPoint(this.position.getX(), this.position.getY());
	}
	
	//Returns the sprite depending on the interval declared in the constructor
	public Sprite returnSprite(float currentTime){
		calculateTransitions(currentTime);
		switch(direction){
			case 0:
				if (animCycle>=spriteUpLeft.length){
					animCycle = 0;
				}
				return new Sprite(spriteUpLeft[animCycle]);
			case 1:
				if (animCycle>=spriteUpRight.length){
					animCycle = 0;
				}
				return  new Sprite(spriteUpRight[animCycle]);
			case 2:
				if (animCycle>=spriteDownLeft.length){
					animCycle = 0;
				}
				return new Sprite(spriteDownLeft[animCycle]);
			case 3:
				if (animCycle>=spriteDownRight.length){
					animCycle = 0;
				};
				return new Sprite(spriteDownRight[animCycle]);
			default:return new Sprite(spriteDownRight[animCycle]);
		}
	}
}
